#include "windowmanager.h"
#include "windowlistener.h"
#include "utils/systemutil.h"

#include <QDebug>
#include <QTimer>
#include <QMetaType>

WindowManager::WindowManager(QObject *parent)
    : QObject(parent)
{
    qRegisterMetaType<WindowInfo>("WindowInfo");
    qRegisterMetaType<QList<WindowInfo>>("QList<WindowInfo>");
}

WindowManager::~WindowManager()
{

}

void WindowManager::start()
{
    stop();
    WindowListener *listener = new WindowListener(this);
    listener->moveToThread(&m_thread);
    connect(&m_thread, &QThread::finished, listener, &QObject::deleteLater);
    connect(this, &WindowManager::enumWindows, listener, &WindowListener::slotEnumWindows);
    connect(this, &WindowManager::onEnumWindows, this, &WindowManager::slotCreateWindow);
    m_thread.start();

    QTimer *timer = new QTimer(this);
    timer->setObjectName("app_timer");
    connect(timer, &QTimer::timeout, this, [ = ] { emit enumWindows(); });
    timer->start(1000);
    // 立即执行一次
    emit enumWindows();
}

void WindowManager::stop()
{
    QTimer *timer = this->findChild<QTimer *>("app_timer");
    if (timer)
    {
        timer->stop();
        timer->deleteLater();
    }

    if (m_thread.isRunning())
    {
        m_thread.quit();
        m_thread.wait();
    }
}

QStringList WindowManager::processList() const
{
    return m_processList;
}

void WindowManager::setProcessList(const QStringList &processList)
{
    m_processList = processList;
}

void WindowManager::slotCreateWindow(const QList<WindowInfo> &windowInfos)
{
    QMutexLocker locker(&m_mutex);
    for (const WindowInfo &windowInfo : windowInfos)
    {
        // 检查是否已经存在水印窗口
        WID wid = windowInfo.windowId();
        if (wid == 0 || m_watermarkWindows.contains(wid))
        {
            continue;
        }

        qDebug() << "create wid:" << wid;

        WatermarkWindow *window = createWatermarkWindow(windowInfo);
        if (!window)
        {
            continue;
        }

        m_watermarkWindows.insert(wid, window);
        connect(window, &WatermarkWindow::quitWindow, this, &WindowManager::slotQuitWindow);
    }
}

void WindowManager::slotQuitWindow(const WID &wid)
{
    QMutexLocker locker(&m_mutex);
    qDebug() << "close wid:" << wid;
    m_watermarkWindows.remove(wid);
}

void WindowManager::slotUpdateWatermarkWindow()
{
    QMutexLocker locker(&m_mutex);
    QMap<WID, WatermarkWindow *>::const_iterator it;
    for (it = m_watermarkWindows.cbegin(); it != m_watermarkWindows.cend(); ++it)
    {
        it.value()->update();
    }
}

void WindowManager::slotOnProcessChanged(const QString &process, int changed)
{
    QMutexLocker locker(&m_mutex);
    if (changed == 0)
    {
        m_processList.append(process);
    }
    else if (changed == 1)
    {
        m_processList.removeOne(process);

        for (auto mapIt = m_watermarkWindows.begin(); mapIt != m_watermarkWindows.end();)
        {
            WatermarkWindow *window = mapIt.value();
            if (window->processName() == process)
            {
                window->disconnect();
                window->deleteLater();
                m_watermarkWindows.erase(mapIt++);
            }
            else
            {
                ++mapIt;
            }
        }
    }
}

#ifdef Q_OS_WIN32
WatermarkWindow *WindowManager::createWatermarkWindow(const WindowInfo &windowInfo)
{
    WID parentHwnd = windowInfo.windowId();

    // 创建水印窗口
    WatermarkWindow *window = new WatermarkWindow();
    window->setProcessName(windowInfo.processName());

    // 将水印窗口依附到指定窗口上，设置水印窗口父节点
    WID hwnd = (WID)window->winId();

    // 获取父窗口大小
    RECT rect;
    GetWindowRect(parentHwnd, &rect);
    QRect targetRect(-rect.left,  -rect.top, rect.right - rect.left, rect.bottom - rect.top);
    window->setVisible(false);
    window->setParentWid(parentHwnd);
    window->setGeometry(targetRect);
    // 设置父节点
    ::SetParent(hwnd, parentHwnd);
    // 显示
    window->show();

    // 获取真实大小
    RECT realRect;
    GetWindowRect(hwnd, &realRect);

    // 定位水印
    int x = SystemUtil::isWinXp() ? 0 : (-rect.left - realRect.left);
    int y = SystemUtil::isWinXp() ? 0 : (-rect.top - realRect.top);
    int width = rect.right - rect.left - realRect.left;
    int height = rect.bottom - rect.top - realRect.top;
    ::MoveWindow(hwnd, x, y, width, height, true);

    return window;
}
#endif
#ifdef Q_OS_LINUX
WatermarkWindow *WindowManager::createWaterWindow(const WindowInfo &windowInfo)
{

}
#endif
